﻿' LibWowArmory
' by Ronald M. Clifford (roncli@roncli.com)
'
' This source code is released under the GNU Library General Public License (LGPL) Version 2.1.

Imports System
Imports System.Collections.Generic
Imports System.IO
Imports System.Linq
Imports System.Web
Imports System.Xml.Serialization

Namespace roncliProductions.LibWowArmory

    ''' <summary>
    ''' A class that retrieves class talents from the armory
    ''' </summary>
    ''' <remarks></remarks>
    Public Class TalentTree
        Inherits WowArmoryData

        Private ttPage As New TalentTreeSchema.page
        Private cClass As Enums.ClassType
        Private lstTalentTrees As New List(Of TalentTree)

        ''' <summary>
        ''' The class to lookup talents for
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property [Class]() As Enums.ClassType
            Get
                Return cClass
            End Get
            Set(ByVal value As Enums.ClassType)
                cClass = value
            End Set
        End Property

        ''' <summary>
        ''' The talent trees for this class
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property TalentTrees() As List(Of TalentTree)
            Get
                Return lstTalentTrees
            End Get
            Set(ByVal value As List(Of TalentTree))
                lstTalentTrees = value
            End Set
        End Property

        ''' <summary>
        ''' The URL that will be used to retrieve the class's talents from the armory
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Overrides ReadOnly Property URL() As String
            Get
                If cClass = ClassType.Unknown Then
                    Return "http://www.wowarmory.com/talent-tree.xml?cid=&loc=en_us"
                Else
                    Return String.Format("http://www.wowarmory.com/talent-tree.xml?cid={0}&loc=en_us", CInt(cClass))
                End If
            End Get
        End Property

        ''' <summary>
        ''' Indicates to the inherited class that this request does not require login
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Overrides ReadOnly Property RequiresLogin() As Boolean
            Get
                Return False
            End Get
        End Property

        ''' <summary>
        ''' A constructor to load a class's talents
        ''' </summary>
        ''' <param name="cClass"></param>
        ''' <remarks></remarks>
        Public Sub New(ByVal cClass As Enums.ClassType)
            Me.cClass = cClass
            Load()
        End Sub

        ''' <summary>
        ''' A constructor to load a class's talents
        ''' </summary>
        ''' <param name="strClass"></param>
        ''' <remarks></remarks>
        Public Sub New(ByVal strClass As String)
            Try
                Me.cClass = CType([Enum].Parse(GetType(Enums.ClassType), strClass.Replace(" ", "")), Enums.ClassType)
            Catch ex As Exception
                Throw New ArgumentException("There is no such class.")
            End Try
            Load()
        End Sub

        ''' <summary>
        ''' Loads the class's talents from the Armory
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub Load()
            Dim strKey As String = String.Format("LibWowArmory.TalentTree.{0}", CInt(cClass))
            If Cache.Cache(strKey) Is Nothing Then
                MyBase.Retrieve()

                Dim xsSerializer As New XmlSerializer(ttPage.GetType())

                Dim srXML As New StringReader(MyBase.strData)

                ttPage = CType(xsSerializer.Deserialize(srXML), TalentTreeSchema.page)

                Cache.Cache.Insert(strKey, ttPage, Nothing, Date.UtcNow.AddDays(1), Nothing, Caching.CacheItemPriority.Normal, Nothing)
            Else
                ttPage = CType(Cache.Cache(strKey), TalentTreeSchema.page)
            End If

            Dim intTalentID As Integer = 0
            Dim ttsTree As TalentTreeSchema.tree
            Dim ttsTalent As TalentTreeSchema.talent
            Dim ttsRank As TalentTreeSchema.rank
            Dim tTree As TalentTree
            Dim tTalent As Talent
            For Each ttsTree In ttPage.talentTrees.First().tree.OrderBy(Function(t) t.order)
                tTree = New TalentTree(ttsTree.name)
                For Each ttsTalent In ttsTree.talent.OrderBy(Function(t) t.tier).ThenBy(Function(t) t.column)
                    tTalent = New Talent(intTalentID, ttsTalent.name, ttsTalent.key, 0, ttsTalent.rank.Count, ttsTalent.column, ttsTalent.tier, ttsTalent.requires)
                    For Each ttsRank In ttsTalent.rank.OrderBy(Function(t) t.level)
                        tTalent.Ranks.Add(ttsRank.description)
                    Next
                    If ttsTalent.spell.Count > 0 Then
                        tTalent.SpellCastTime = ttsTalent.spell.First().castTime
                        tTalent.SpellCooldown = ttsTalent.spell.First().cooldown
                        tTalent.SpellMaxRange = ttsTalent.spell.First().maxRange
                        If ttsTalent.spell.First().power.Count > 0 Then
                            For Each pPower As TalentTreeSchema.power In ttsTalent.spell.First().power
                                tTalent.RequiredPower.Add(New Power(pPower.cost, pPower.type))
                            Next
                        End If
                    End If
                    tTree.Talents.Add(tTalent)
                    intTalentID += 1
                Next
                lstTalentTrees.Add(tTree)
            Next
        End Sub

        ''' <summary>
        ''' Retrieves the talent by its talent ID
        ''' </summary>
        ''' <param name="intTalentID"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function GetTalentByID(ByVal intTalentID As Integer) As Talent
            Dim varTalents = lstTalentTrees.SelectMany(Function(t) t.Talents).Where(Function(t) t.TalentID = intTalentID)
            If varTalents.Count = 0 Then
                'Throw New ArgumentOutOfRangeException("intTalentID", "The talent ID does not exist for this class.")
                Return Nothing
            Else
                Return varTalents.First()
            End If
        End Function

        ''' <summary>
        ''' A class that encapsulates a talent
        ''' </summary>
        ''' <remarks></remarks>
        Public Class Talent

            Private intTalentID As Integer
            Private strName As String
            Private strKey As String
            Private intPoints As Integer
            Private intMaxPoints As Integer
            Private intTreeColumn As Integer
            Private intTreeRow As Integer
            Private strRequiredTalentKey As String
            Private dblSpellCastTime As Double
            Private intSpellCooldown As Integer
            Private intSpellMaxRange As Integer
            Private lstRanks As New List(Of String)
            Private lstRequiredPower As New List(Of Power)

            ''' <summary>
            ''' The ID number of the talent
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property TalentID() As Integer
                Get
                    Return intTalentID
                End Get
                Set(ByVal value As Integer)
                    intTalentID = value
                End Set
            End Property

            ''' <summary>
            ''' The name of this talent
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property Name() As String
                Get
                    Return strName
                End Get
                Set(ByVal value As String)
                    strName = value
                End Set
            End Property

            ''' <summary>
            ''' The key that Blizzard uses to identify this talent
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property Key() As String
                Get
                    Return strKey
                End Get
                Set(ByVal value As String)
                    strKey = value
                End Set
            End Property

            ''' <summary>
            ''' The number of points the character has put into this talent
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property Points() As Integer
                Get
                    Return intPoints
                End Get
                Set(ByVal value As Integer)
                    intPoints = value
                End Set
            End Property

            ''' <summary>
            ''' The maximum number of points that can be put into this talent
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property MaxPoints() As Integer
                Get
                    Return intMaxPoints
                End Get
                Set(ByVal value As Integer)
                    intMaxPoints = value
                End Set
            End Property

            ''' <summary>
            ''' The tree's column that the talent appears in
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property TreeColumn() As Integer
                Get
                    Return intTreeColumn
                End Get
                Set(ByVal value As Integer)
                    intTreeColumn = value
                End Set
            End Property

            ''' <summary>
            ''' The tree's row that the talent appears in
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property TreeRow() As Integer
                Get
                    Return intTreeRow
                End Get
                Set(ByVal value As Integer)
                    intTreeRow = value
                End Set
            End Property

            ''' <summary>
            ''' The key of the talent that is required to take this talent
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property RequiredTalentKey() As String
                Get
                    Return strRequiredTalentKey
                End Get
                Set(ByVal value As String)
                    strRequiredTalentKey = value
                End Set
            End Property

            ''' <summary>
            ''' The amount of time it takes to cast this talent's spell
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property SpellCastTime() As Double
                Get
                    Return dblSpellCastTime
                End Get
                Set(ByVal value As Double)
                    dblSpellCastTime = value
                End Set
            End Property

            ''' <summary>
            ''' The cooldown on this talent's spell in milliseconds
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property SpellCooldown() As Integer
                Get
                    Return intSpellCooldown
                End Get
                Set(ByVal value As Integer)
                    intSpellCooldown = value
                End Set
            End Property

            ''' <summary>
            ''' The maximum range of this talent's spell in yards
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property SpellMaxRange() As Integer
                Get
                    Return intSpellMaxRange
                End Get
                Set(ByVal value As Integer)
                    intSpellMaxRange = value
                End Set
            End Property

            ''' <summary>
            ''' The HTML text that describes each rank's abilities
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property Ranks() As List(Of String)
                Get
                    Return lstRanks
                End Get
                Set(ByVal value As List(Of String))
                    lstRanks = value
                End Set
            End Property

            ''' <summary>
            ''' The list of required power needed to cast this talent's spell
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property RequiredPower() As List(Of Power)
                Get
                    Return lstRequiredPower
                End Get
                Set(ByVal value As List(Of Power))
                    lstRequiredPower = value
                End Set
            End Property

            ''' <summary>
            ''' A constructor to create new talent information
            ''' </summary>
            ''' <param name="intTalentID"></param>
            ''' <param name="strName"></param>
            ''' <param name="strKey"></param>
            ''' <param name="intPoints"></param>
            ''' <param name="intMaxPoints"></param>
            ''' <param name="intTreeColumn"></param>
            ''' <param name="intTreeRow"></param>
            ''' <param name="strRequiredTalentKey"></param>
            ''' <remarks></remarks>
            Public Sub New(ByVal intTalentID As Integer, ByVal strName As String, ByVal strKey As String, ByVal intPoints As Integer, ByVal intMaxPoints As Integer, ByVal intTreeColumn As Integer, ByVal intTreeRow As Integer, ByVal strRequiredTalentKey As String)
                Me.intTalentID = intTalentID
                Me.strName = strName
                Me.strKey = strKey
                Me.intPoints = intPoints
                Me.intMaxPoints = intMaxPoints
                Me.intTreeColumn = intTreeColumn
                Me.intTreeRow = intTreeRow
                Me.strRequiredTalentKey = strRequiredTalentKey
            End Sub

        End Class

        ''' <summary>
        ''' A class that encapsulates a talent tree
        ''' </summary>
        ''' <remarks></remarks>
        Public Class TalentTree

            Private strName As String
            Private lstTalents As New List(Of Talent)

            ''' <summary>
            ''' The name of the talent tree
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property Name() As String
                Get
                    Return strName
                End Get
                Set(ByVal value As String)
                    strName = value
                End Set
            End Property

            ''' <summary>
            ''' The tree's talents
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property Talents() As List(Of Talent)
                Get
                    Return lstTalents
                End Get
                Set(ByVal value As List(Of Talent))
                    lstTalents = value
                End Set
            End Property

            ''' <summary>
            ''' A constructor to create a new talent tree
            ''' </summary>
            ''' <param name="strName"></param>
            ''' <remarks></remarks>
            Public Sub New(ByVal strName As String)
                Me.strName = strName
            End Sub

        End Class

        ''' <summary>
        ''' A class that encapsulates power information
        ''' </summary>
        ''' <remarks></remarks>
        Public Class Power

            Private intCost As Integer
            Private strType As String

            ''' <summary>
            ''' The required cost for this power.  This is percent of base for mana, number of runes for death knight runes, and the value for energy, rage, or runic power.
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property Cost() As Integer
                Get
                    Return intCost
                End Get
                Set(ByVal value As Integer)
                    intCost = value
                End Set
            End Property

            ''' <summary>
            ''' The type of power
            ''' </summary>
            ''' <value></value>
            ''' <returns></returns>
            ''' <remarks></remarks>
            Public Property Type() As String
                Get
                    Return strType
                End Get
                Set(ByVal value As String)
                    strType = value
                End Set
            End Property

            ''' <summary>
            ''' A constructor to create new power information
            ''' </summary>
            ''' <param name="intCost"></param>
            ''' <param name="strType"></param>
            ''' <remarks></remarks>
            Public Sub New(ByVal intCost As Integer, ByVal strType As String)
                Me.intCost = intCost
                Me.strType = strType
            End Sub

        End Class

    End Class

End Namespace